// ==UserScript==
// @name          nTubeifier
// @description   Redirects you from YouTube to nTube.
// @priority	  8900
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @grant GM_addStyle
// @run-at 		  document-start
// @version       1.0.6
// @match 		  https://*/*
// @match 		  http://*/*
// @include	      *
// @require https://raw.github.com/odyniec/MonkeyConfig/master/monkeyconfig.js
// ==/UserScript==

function accquire_settings(obj) {
	if (typeof MonkeyConfig === "function") {
		return new MonkeyConfig(obj);
	} else {
		return {
			get: function (key) {
				return null;
			},
			set: function (key, value) {},
		};
	}
}

const cfg = accquire_settings({
	title: "nTubeifier Settings",
	menuCommand: true,
	params: {
		instance_url: {
			label: "Instance URL",
			type: "text",
			default: "http://127.0.0.1:8080/",
		},
	},
});

function read_setting(key, fallback) {
	var read = cfg.get(key);
	if (read == null || read == undefined) {
		return fallback;
	}
	return read;
}

if (!String.prototype.contains) {
	String.prototype.contains = function (str) {
		return this.indexOf(str) > -1;
	};
}

function getQueryVariable(variable) {
	var query = window.location.search.substring(1);
	var vars = query.split("&");
	for (var i = 0; i < vars.length; i++) {
		var pair = vars[i].split("=");
		if (decodeURIComponent(pair[0]) == variable) {
			return decodeURIComponent(pair[1]);
		}
	}
	return null;
}

function getQueryVariableString(string, variable) {
	var query = string.substring(string.indexOf("?") + 1);
	var vars = query.split("&");
	for (var i = 0; i < vars.length; i++) {
		var pair = vars[i].split("=");
		if (decodeURIComponent(pair[0]) == variable) {
			return decodeURIComponent(pair[1]);
		}
	}
	return null;
}

const _URL_EXPRESSION = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;

function isValidYTURL(str) {
	if (str === null || str === undefined || str.length === 0) {
		return false;
	} else {
		var _expr = new RegExp(_URL_EXPRESSION);
		if (!str.match(_expr)) {
			return false;
		} else {
			return (
				str.contains("youtu.be") ||
				str.contains("consent.youtube.com/m?continue=https%3A%2F%2Fwww.youtube.com%2Fwatch") ||
				str.contains("youtube.com/embed/") ||
				str.contains("youtube.com/live/") ||
				str.contains("youtube-nocookie.com/embed/") ||
				(str.contains("youtube.com") && str.contains("v=")) ||
				(str.contains("https://www.google.com/url?") && str.contains("&url=https%3A%2F%2Fwww.youtube.com"))
			);
		}
	}
}

function getVideoInfoFromURL(str) {
	if (!isValidYTURL(str)) {
		return {
			error: true,
			reason: "INVALID_URL",
			type: "invalid",
			url: str,
		};
	} else {
		if (str.contains("youtu.be") || str.contains("youtube.com/embed/") || str.contains("youtube-nocookie.com/embed/") || str.contains("youtube.com/live/")) {
			if (str.contains("watch?v")) {
				// We shouldn't be here.
				return getVideoInfoFromURL(str);
			} else if (str.contains("?enablejsapi=1")) {
				return {
					error: true,
					reason: "INVALID_URL",
					type: "invalid",
					url: str,
				};
			} else {
				var type;
				if (str.contains("youtube.com/embed/") || str.contains("youtube-nocookie.com/embed/")) {
					type = "embed";
				} else if (str.contains("youtube.com/live/")) {
					type = "live";
				} else {
					type = "short";
				}
				if (str.contains("?")) {
					return {
						id: str.substring(str.lastIndexOf("/") + 1, str.lastIndexOf("?")),
						playlist_id: getQueryVariableString(str, "playlist"),
						time: getQueryVariableString(str, "t"),
						type: type,
					};
				} else {
					return {
						id: str.substring(str.lastIndexOf("/") + 1),
						playlist_id: getQueryVariableString(str, "playlist"),
						time: getQueryVariableString(str, "t"),
						type: type,
					};
				}
			}
		} else if (str.contains("consent.youtube.com/m?continue=https%3A%2F%2Fwww.youtube.com%2Fwatch")) {
			var newURL = getQueryVariable(str, "continue");
			var videoID = getQueryVariableString(newURL, "v");
			var time = getQueryVariableString(newURL, "t");
			return {
				id: videoID,
				time: time,
				type: "standard-consent",
			};
		} else if (str.contains("youtube.com") && str.contains("v=")) {
			const _id = getQueryVariableString(str, "v");
			if (_id === null || _id === undefined) {
				return {
					error: true,
					reason: "UNKNOWN_URL_TYPE",
					url: str,
					type: "invalid",
				};
			} else {
				return {
					id: _id,
					playlist_id: getQueryVariableString(str, "playlist"),
					time: getQueryVariableString(str, "t"),
					type: "standard",
				};
			}
		} else if (str.contains("https://www.google.com/url?") && str.contains("&url=https%3A%2F%2Fwww.youtube.com")) {
			const _url = getQueryVariableString(str, "url");
			return getVideoInfoFromURL(_url);
		} else {
			return {
				error: true,
				reason: "UNKNOWN_URL_TYPE",
				url: str,
				type: "invalid",
			};
		}
	}
}

function stopLoading() {
	if (typeof window.stop === "function") {
		window.stop();
	}
}

function check() {
	const URL = document.URL;
	const instanceURL = read_setting("instance_url", "http://127.0.0.1:8080/");
	console.debug(URL);
	var info = getVideoInfoFromURL(URL);
	if (info === null || info === undefined || !info["type"] || info["type"] === "invalid") {
		return;
	} else {
		stopLoading();
		var newURL;
		var time = info["time"];
		var playlist = info["playlist_id"];
		if (info["type"] === "embed") {
			newURL = instanceURL + "embed?v=" + info["id"];
		} else if (info["type"] === "standard" || info["type"] === "standard-consent") {
			newURL = instanceURL + "watch?v=" + info["id"] + "&redirect=from_script_popup";
			if (time !== null && time !== undefined) {
				newURL += "&t=" + time;
			}
			if (playlist !== null && playlist !== undefined) {
				newURL += "&list=" + playlist;
			}
		} else if (info["type"] === "short" || info["type"] === "live") {
			newURL = instanceURL + "watch?v=" + info["id"] + "&redirect=from_script_popup";
			if (time !== null && time !== undefined && info["type"] !== "live") {
				newURL += "&t=" + time;
			}
			if (playlist !== null && playlist !== undefined) {
				newURL += "&list=" + playlist;
			}
		} else {
			throw new Error("Invalid type: " + info["type"]);
		}
		document.location.href = newURL;
	}
}

(function () {
	if (window.Promise) {
		new Promise(check);
	} else {
		check();
	}
})();
